package com.allwees.bs.c.module.user.service.impl;

import com.allwees.bs.c.module.sys.entity.DivisionEntity;
import com.allwees.bs.c.module.sys.repository.DivisionRepository;
import com.allwees.bs.c.module.user.dto.RegionDto;
import com.allwees.bs.c.module.user.dto.ShippingAddressDTO;
import com.allwees.bs.c.module.user.dto.UserDto;
import com.allwees.bs.c.module.user.entity.ShippingAddressEntity;
import com.allwees.bs.c.module.user.mapper.ShippingAddressMapper;
import com.allwees.bs.c.module.user.repository.ShippingAddressRepository;
import com.allwees.bs.c.module.user.req.*;
import com.allwees.bs.c.module.user.service.IShippingAddressService;
import com.allwees.bs.c.module.user.service.IUserService;
import com.allwees.bs.core.model.user.constant.EUserSourceType;
import com.allwees.bs.core.modelbase.constant.ResultEnum;
import com.allwees.bs.core.modelbase.exception.BusinessException;
import com.allwees.bs.core.modelbase.page.PageParams;
import com.allwees.bs.core.modelbase.page.PaginateDTO;
import com.allwees.core.common.constant.EDelete;
import com.allwees.core.common.util.reflect.PojoUtil;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ShippingAddressServiceImpl implements IShippingAddressService {

    @Resource
    private ShippingAddressRepository shippingAddressRepository;
    @Autowired
    private ShippingAddressMapper shippingAddressMapper;
    @Autowired
    private DivisionRepository divisionRepository;
    @Autowired
    private IUserService userService;

    private Map<String, DivisionEntity> divisionEntityMap;

    @Override
    @Transactional
    public ShippingAddressDTO addShippingAddress(String userUuid, ShippingAddressReq shippingAddressReq) {
        ShippingAddressEntity shippingAddress = shippingAddressReq.map2Entity();
        shippingAddress.setUserUuid(userUuid);

        // 如果新增收货地址为默认，则需要把以前的默认地址修改为非默认
        if (shippingAddress.getIsDefault() == 1) {
            this.shippingAddressRepository.changeDefault2NoN(userUuid);
        }

        // 保存新收货地址
        autoComplementRegionName(shippingAddress);
        this.shippingAddressRepository.save(shippingAddress);

        return this.shippingAddressMapper.entity2DTO(shippingAddress);
    }

    @Override
    public ShippingAddressDTO getShippingAddress(String userUuid, String addressUuid) {
        ShippingAddressEntity shippingAddress = this.shippingAddressRepository.getByUuid(addressUuid);
        if (shippingAddress == null) {
            throw BusinessException.getInstance(ResultEnum.NOT_FOUND);
        }
        // 获取的不是自己的收货地址
        if (!shippingAddress.getUserUuid().equals(userUuid)) {
            throw BusinessException.getInstance(ResultEnum.UNAUTHORIZED);
        }
        return this.shippingAddressMapper.entity2DTO(shippingAddress);
    }

    @Override
    public ShippingAddressDTO getDefaultShippingAddress(String userUuid) {
        ShippingAddressEntity defaultShippingAddressEntity = this.shippingAddressRepository.findDefaultShippingAddress(userUuid);
        return this.shippingAddressMapper.entity2DTO(defaultShippingAddressEntity);
    }

    @Override
    public PaginateDTO<ShippingAddressDTO> getAllShippingAddress(String userUuid) {
        List<ShippingAddressEntity> shippingAddressList = this.shippingAddressRepository.findUserAllShippingAddress(userUuid);
        // 直接获取了用户的所有收货地址，所以总数就是列表的长度，并新建一个翻页参数数据
        return this.shippingAddressMapper.entity2DTO(shippingAddressList, shippingAddressList.size(), new PageParams());
    }

    @Override
    public ShippingAddressDTO updateShippingAddress(String userUuid, String addressID, ShippingAddressReq shippingAddressReq) {
        ShippingAddressEntity shippingAddress = this.shippingAddressRepository.getByUuid(addressID);
        if (shippingAddress == null) {
            throw BusinessException.getInstance(ResultEnum.NOT_FOUND);
        }

        // 如果修改收货地址为默认，则需要把以前的默认地址修改为非默认
        if (shippingAddressReq.getIsDefault()) {
            this.shippingAddressRepository.changeDefault2NoN(userUuid);
        } else {
            ShippingAddressEntity defaultShippingAddress = shippingAddressRepository.findDefaultShippingAddress(userUuid);
            if (null == defaultShippingAddress || StringUtils.isBlank(defaultShippingAddress.getUuid())) {
                log.info("无法获取默认配置...{}", userUuid);
            } else {
                if (shippingAddress.getUuid().equals(defaultShippingAddress.getUuid())) {
                    throw BusinessException.getInstance(ResultEnum.AT_LEAST_ONE_DEFAULT);
                }
            }
        }

        // 更新数据
        shippingAddressReq.map2Entity(shippingAddress);

        autoComplementRegionName(shippingAddress);
        this.shippingAddressRepository.save(shippingAddress);

        return this.shippingAddressMapper.entity2DTO(shippingAddress);
    }

    @Override
    public void deleteShippingAddress(String userUuid, String addressUuid) {
        ShippingAddressEntity sippingAddressEntity = this.shippingAddressRepository.getByUuid(addressUuid);
        if (sippingAddressEntity == null) {
            throw BusinessException.getInstance(ResultEnum.NOT_FOUND);
        }
        if (!sippingAddressEntity.getUserUuid().equals(userUuid)) {
            throw BusinessException.getInstance(ResultEnum.DATA_NO_PRIVILEGE);
        }

        // 收货地址只做软删除
        sippingAddressEntity.setIsDeleted(EDelete.DELETED.value());
        sippingAddressEntity.setDeletedAt(new Date());

        //delete error
        this.shippingAddressRepository.save(sippingAddressEntity);
    }

    @Override
    public UserDto visitorAddShippingAddress(VisitorShippingAddressReq req) {
        RegisterReq registerReq = RegisterReq.build(
                req.getEmail(),
                req.getFirstName(),
                req.getLastName(),
                EUserSourceType.of(req.getPlatform()),
                req.getShareCode(),
                req.getInviteChannel());

        UserDto userDto = userService.visitorRegister(registerReq);
        addShippingAddress(userDto.getUuid(), PojoUtil.copy(new ShippingAddressReq(), req));
        return userDto;
    }

    @Override
    @Transactional
    public void updateDefault(String userUuid, String addressUuid, ShippingAddressUpdateDefaultReq req) {
        ShippingAddressEntity shippingAddress = shippingAddressRepository.getByUuid(addressUuid);
        if (shippingAddress == null || !shippingAddress.getUserUuid().equals(userUuid)) {
            throw BusinessException.getInstance(ResultEnum.NOT_FOUND);
        }
        if (req.isDef()) {
            shippingAddressRepository.changeDefault2NoN(userUuid);
        }

        shippingAddress.setIsDefault(req.isDef() ? 1 : 0);
        shippingAddressRepository.save(shippingAddress);
    }

    @Override
    public List<RegionDto> findSubRegionList(RegionReq regionReq) {
        String regionId = regionReq.getRegionId();
        List<RegionDto> regionDtoList = Lists.newArrayList();
        List<DivisionEntity> divisionEntities;
        if (StringUtils.isBlank(regionId)) {
            divisionEntities = divisionRepository.findByLayer(2);
        } else {
            DivisionEntity entity = divisionEntityMap.get(regionId);
            divisionEntities = divisionRepository.findRegion(entity.getDivisionCode() + ".", entity.getLayer() + 1);
        }

        divisionEntities.forEach(t -> {
            RegionDto regionDto = new RegionDto();
            regionDto.setRegionId(t.getId() + "").setName(t.getName()).setOldName(t.getOldName());
            regionDtoList.add(regionDto);
        });

        regionDtoList.sort(Comparator.comparing(RegionDto::getName));

        return regionDtoList;
    }

    /**
     * 自动设置名称
     *
     * @param sippingAddress 用户地址
     */
    private void autoComplementRegionName(ShippingAddressEntity sippingAddress) {
        sippingAddress.setCountry(getDivisionEntityName(sippingAddress.getCountryId()));
        sippingAddress.setProvince(getDivisionEntityName(sippingAddress.getProvinceId()));
        sippingAddress.setCity(getDivisionEntityName(sippingAddress.getCityId()));
        sippingAddress.setDistrict(getDivisionEntityName(sippingAddress.getDistrictId()));
    }

    /**
     * 得到名称
     *
     * @param divisionEntityId 主键ID
     * @return
     */
    private String getDivisionEntityName(Integer divisionEntityId) {
        DivisionEntity divisionEntity = divisionEntityMap.get("" + divisionEntityId);
        if (null == divisionEntity) {
            throw BusinessException.getInstance(ResultEnum.NOT_FOUND);
        } else {
            return divisionEntity.getName();
        }
    }

    @PostConstruct
    public void setApplicationContext() throws BeansException {
        log.info("初始化地区配置...");
        divisionEntityMap = divisionRepository.findAll().stream().collect(Collectors.toMap(t -> t.getId() + "", Function.identity()));
    }
}
